﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace CSharpExperiments
{
	public static class Swap
	{
		public static Swap<A> For<A>(A obj)
		{
			return new Swap<A>(obj);
		}

		public static Swap<String> If(this Swap<String> swap, Regex regex, String val)
		{
			return swap.If(x => regex.IsMatch(x), val);
		}

		public static Swap<String> If(this Swap<String> swap, Regex regex, Func<String> val)
		{
			return swap.If(x => regex.IsMatch(x), val);
		}

		public static Swap<String> If(this Swap<String> swap, Regex regex, Func<String, String> val)
		{
			return swap.If(x => regex.IsMatch(x), val);
		}

		public static Swap<String> IfRegex(this Swap<String> swap, String regex, String val)
		{
			return swap.If(x => Regex.IsMatch(x, regex), val);
		}

		public static Swap<String> IfRegex(this Swap<String> swap, String regex, Func<String> val)
		{
			return swap.If(x => Regex.IsMatch(x, regex), val);
		}

		public static Swap<String> IfRegex(this Swap<String> swap, String regex, Func<String, String> val)
		{
			return swap.If(x => Regex.IsMatch(x, regex), val);
		}
	}

	public struct Swap<A>
	{
		private A key;
		private A result;
		private bool done;

		public Swap(A originalKey) : this()
		{
			key = originalKey;
			result = originalKey;
			done = false;
		}

		public Swap<A> If(Func<A, bool> predicate, Func<A, A> resultFactory)
		{
			if (!done && predicate(key))
			{
				result = resultFactory(key);
				done = true;
			}

			return this;
		}

		public A Result
		{
			get { return result; }
		}

		public static implicit operator A(Swap<A> swap)
		{
			return swap.result;
		}

		public Swap<A> If(A compare, A val)
		{
			return If(x => Object.Equals(x, compare), x => val);
		}

		public Swap<A> If(bool cond, A val)
		{
			return If(x => cond, x => val);
		}

		public Swap<A> If(Func<bool> cond, A val)
		{
			return If(x => cond(), x => val);
		}

		public Swap<A> If(Func<A, bool> cond, A val)
		{
			return If(cond, x => val);
		}

		public Swap<A> If(A compare, Func<A> val)
		{
			return If(x => Object.Equals(x, compare), x => val());
		}

		public Swap<A> If(bool cond, Func<A> val)
		{
			return If(x => cond, x => val());
		}

		public Swap<A> If(Func<bool> cond, Func<A> val)
		{
			return If(x => cond(), x => val());
		}

		public Swap<A> If(Func<A, bool> cond, Func<A> val)
		{
			return If(cond, x => val());
		}

		public Swap<A> If(A compare, Func<A, A> val)
		{
			return If(x => Object.Equals(x, compare), val);
		}

		public Swap<A> If(bool cond, Func<A, A> val)
		{
			return If(x => cond, val);
		}

		public Swap<A> If(Func<bool> cond, Func<A, A> val)
		{
			return If(x => cond(), val);
		}
	}
}
